package com.fany.views.circlemenu;

import java.util.ArrayList;

import com.fany.constants.StringResources;
import com.fany.fastsearcher.R;
import com.fany.utils.AlgorithmUtils;
import com.fany.utils.BitmapHelper;
import com.fany.utils.ShapeUtils;
import com.fany.utils.SystemUtils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

public class CircleMenuViewAdvanced extends View
{
    private CircleMenuItem touchedItem;
    private ArrayList<CircleMenuItem> _items;
    private CircleArea _menuArea;
    private boolean _isMenuTouching;
    private boolean _isShowMenus = true;

    private Paint _paint;
    private int _innerRingColor = Color.WHITE;
    private int _outerRingColor = Color.BLUE;

    private CircleArea _controlArea;

    private boolean _isControlAimTouching;
    private CircleArea _controlAimArea;
    private int _controlAimAngle;

    private boolean _isControlButtonTouching;
    private CircleMenuControlButton _controlButton;

    private PointF _touchPoint;
    private PointF _movePoint;

    public OnAngleChangedListener angleChangedListener;
    public OnButtonClickListener buttonClickListener;

    public void setIsShowMenus(boolean value)
    {
        if (value != _isShowMenus)
        {
            _isShowMenus = value;
            invalidate();
        }
    }

    public boolean getIsShowMenus()
    {
        return _isShowMenus;
    }

    public CircleMenuViewAdvanced(Context context)
    {
        super(context);
        _items = new ArrayList<CircleMenuItem>();
        _paint = new Paint();

        int screenWidth = SystemUtils.getScreenWidth();
        int screenHeight = SystemUtils.getScreenHeight();

        _menuArea = new CircleArea();
        _menuArea.adjustArea(new PointF((int) (screenWidth * 0.75), (int) (screenWidth * 0.25)),
                (int) (screenWidth * 0.5));

        _controlArea = new CircleArea();
        _controlArea.adjustArea(new PointF((int) (screenWidth * 0.3), (int) (screenHeight * 0.6)),
                (int) (screenWidth * 0.25));

        _controlAimArea = new CircleArea();
        adjustControllerAimArea(0);

        _controlButton = new CircleMenuControlButton(this.getContext(), _controlArea.centerPoint,
                (_controlArea.radius - 90));
    }

    private void adjustControllerAimArea(int angle)
    {
        _controlAimAngle = angle;
        PointF center = AlgorithmUtils.calculateCirclePoint(_controlArea.centerPoint, _controlArea.radius, angle);
        final int controllerAimRadius = 60;
        _controlAimArea.adjustArea(center, controllerAimRadius);
    }

    public void addItem(String Text, int resourceId, int commandId)
    {
        CircleMenuItem item = new CircleMenuItem(_menuArea);
        _items.add(item);
        item.setBitmap( BitmapHelper.loadBitmapResource(resourceId) );
        item.text = Text;
        item.commandId = commandId;
        adjustItemAngle();
        invalidate();
    }

    private void adjustItemAngle()
    {
        int angle = 0;
        int degreeDelta = 360 / _items.size();
        for (int index = 0; index < _items.size(); index++)
        {
            _items.get(index).setAngle(angle);
            angle += degreeDelta;
            _items.get(index).adjustItemCoordinate();
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent e)
    {
        switch (e.getAction() & MotionEvent.ACTION_MASK)
        {
            case MotionEvent.ACTION_DOWN:
                for (int i = 0; i < _items.size(); i++)
                {
                    if (_isShowMenus && _items.get(i).isPointInMenu(new PointF(e.getX(), e.getY())))
                    {
                        touchedItem = _items.get(i);
                        break;
                    }
                }
                _isMenuTouching = _menuArea.isPointInArea(e.getX(), e.getY());
                _isControlAimTouching = _controlAimArea.isPointInArea(e.getX(), e.getY());
                _isControlButtonTouching = _controlButton.isPointInButton(e.getX(), e.getY());
                _touchPoint = new PointF(e.getX(0), e.getY(0));
                _movePoint = new PointF(e.getX(0), e.getY(0));
                return (_isShowMenus && _isMenuTouching) || _isControlAimTouching || _isControlButtonTouching;
            case MotionEvent.ACTION_MOVE:
                double distance = AlgorithmUtils.calculateDistance(new PointF(e.getX(0), e.getY(0)), _touchPoint);
                if (distance > 100)
                {
                    changeFocusItem(e.getX(), e.getY());
                    if (_isMenuTouching)
                    {
                        performMenuMoved(e);
                    }
                    if (_isControlAimTouching)
                    {
                        performControlAimMoved(e);
                    }
                }
                _movePoint = new PointF(e.getX(0), e.getY(0));
                break;
            case MotionEvent.ACTION_UP:
                _isMenuTouching = false;
                _isControlAimTouching = false;
                if (_isControlButtonTouching)
                {
                    if (_controlButton.isPointInButton(e.getX(), e.getY()))
                    {
                        performClickControlButton();
                    }
                }
                _isControlButtonTouching = false;
                break;
        }
        return false;
    }

    private void performMenuMoved(MotionEvent e)
    {
        int startAngle = AlgorithmUtils.computeAngle(_menuArea.centerPoint, _movePoint.x, _movePoint.y);
        int endAngle = AlgorithmUtils.computeAngle(_menuArea.centerPoint, e.getX(), e.getY());
        int angle = endAngle - startAngle;
        resetItemsAngle(angle);
        invalidate();
    }

    private void performControlAimMoved(MotionEvent e)
    {
        int startAngle = AlgorithmUtils.computeAngle(_controlArea.centerPoint, _movePoint.x, _movePoint.y);
        int endAngle = AlgorithmUtils.computeAngle(_controlArea.centerPoint, e.getX(), e.getY());
        int angle = endAngle - startAngle;
        if (Math.abs(angle) > 180)
        {
            angle = 360 - Math.abs(startAngle - endAngle);
        }
        adjustControllerAimArea(_controlAimAngle + angle);
        if (_isShowMenus)
        {
            resetItemsAngle(angle);
        }
        else
        {
            if (angleChangedListener != null)
            {
                angleChangedListener.onAngleChanged(angle);
            }
        }
        invalidate();
    }

    private void changeFocusItem(float x, float y)
    {
        if (_items.size() == 0)
        {
            return;
        }
        int angleOffset = 360 / _items.size() / 2;
        int angle = 90 + (int) AlgorithmUtils.calculateTriangleAngle(_menuArea.centerPoint.x
                - _controlArea.centerPoint.x, _controlArea.centerPoint.y - _menuArea.centerPoint.y);
        for (CircleMenuItem item : _items)
        {
            item.focused = (Math.abs(item.getAngle() - angle) % 360) < angleOffset;
        }
    }

    private void performClickControlButton()
    {
        if (_isShowMenus)
        {
            for (CircleMenuItem item : _items)
            {
                if (item.focused)
                {
                    touchedItem = item;
                    break;
                }

            }
            if (touchedItem == null)
            {
                Toast.makeText(this.getContext(), StringResources.SelectOperation, Toast.LENGTH_SHORT).show();
            }
        }
        else
        {
            if (buttonClickListener != null)
            {
                buttonClickListener.onButtonClick();
            }
        }
    }

    @Override
    public void onDraw(Canvas canvas)
    {
        if (_isShowMenus)
        {
            drawRing(canvas);

            for (int index = 0; index < _items.size(); index++)
            {
                CircleMenuItem item = _items.get(index);
                if (item.visible)
                {
                    drawItem(canvas, item);
                }
            }
        }
        drawController(canvas);
    }

    private void drawRing(Canvas canvas)
    {
        _paint.setAntiAlias(true);
        _paint.setColor(_innerRingColor);
        _paint.setStyle(Paint.Style.FILL);
        _paint.setAlpha(0x30);
        canvas.drawCircle(_menuArea.centerPoint.x, _menuArea.centerPoint.y, _menuArea.radius - 80, _paint);

        _paint.setAntiAlias(true);
        _paint.setColor(_outerRingColor);
        _paint.setStyle(Paint.Style.FILL);
        _paint.setAlpha(0x30);
        canvas.drawCircle(_menuArea.centerPoint.x, _menuArea.centerPoint.y, _menuArea.radius + 40, _paint);
    }

    void drawItem(Canvas canvas, CircleMenuItem item)
    {
        _paint.setColor(Color.WHITE);
        _paint.setTextSize(SystemUtils.getScreenWidth() / 18);
        Rect itemRect = item.getItemRect();
        if (item.focused)
        {
            ShapeUtils.scaleRect(itemRect, 1.6f);
            _paint.setTextSize(SystemUtils.getScreenWidth() / 15);
        }
        Bitmap bitmap = item.getBitmap();
        canvas.drawBitmap(bitmap, null, itemRect, null);
        Rect rect = new Rect();
        _paint.getTextBounds(item.text, 0, item.text.length(), rect);
        canvas.drawText(item.text, item.x - rect.width() / 2, itemRect.bottom + rect.height(), _paint);
    }

    private void drawController(Canvas canvas)
    {
        _paint.setAntiAlias(true);
        _paint.setColor(_innerRingColor);
        _paint.setStyle(Paint.Style.FILL);
        _paint.setAlpha(0x30);
        canvas.drawCircle(_controlArea.centerPoint.x, _controlArea.centerPoint.y, _controlArea.radius - 90, _paint);

        _paint.setAntiAlias(true);
        _paint.setColor(_outerRingColor);
        _paint.setStyle(Paint.Style.FILL);
        _paint.setAlpha(0x30);
        canvas.drawCircle(_controlArea.centerPoint.x, _controlArea.centerPoint.y, _controlArea.radius, _paint);

        _controlButton.draw(canvas);

        Bitmap bitmap =  BitmapHelper.loadBitmapResource(R.drawable.ring)  ;
        canvas.drawBitmap(bitmap, null, _controlAimArea.area, null);
    }

    private void resetItemsAngle(int angle)
    {
        for (CircleMenuItem item : _items)
        {
            item.setAngle(item.getAngle() + angle);
            item.adjustItemCoordinate();
        }
    }

    public CircleMenuItem getTouchedItem()
    {
        return touchedItem;
    }

    public void cleanTouchedItem()
    {
        touchedItem = null;
    }

    public void setRingColor(int innerRing, int outerRing)
    {
        _innerRingColor = innerRing;
        _outerRingColor = outerRing;
    }
}
